#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <semaphore.h>


typedef struct linkdata
{
	int code;
	char name[32];
	char inputdata[128];
}userdata;

typedef struct link
{
	userdata data;
	struct sockaddr_in useraddr;
	int Useracceptfd;
	struct link *next;
}user_node;

void *acceptpthread(void *arg);
void *chatfunc(void *arg);
user_node *creat(void);
int insert(user_node *H,userdata Userdata,struct sockaddr_in Useraddr,int Useraccfd);

int sockfd=0;
struct sockaddr_in serveraddr,clientaddr;
socklen_t len=sizeof(serveraddr);
struct sockaddr_in UserAddr;
int Useracc=0;
sem_t sem1;
sem_t sem2;

struct epoll_event events[5];
int epfd = 0;
struct epoll_event event;
user_node *H=NULL;

int main(int argc, const char *argv[])
{
	pthread_t mythread1;
	pthread_t mythread2;
	sem_init(&sem1,0,1);
	sem_init(&sem2,0,0);

	H=creat();
	epfd = epoll_create(5);

	sockfd=socket(AF_INET,SOCK_STREAM,0);
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
	serveraddr.sin_port=htons(atoi(argv[2]));
	bind(sockfd,(struct sockaddr *)&serveraddr,len);
	listen(sockfd,5);

	pthread_create(&mythread1,NULL,&acceptpthread,NULL);
	pthread_create(&mythread2,NULL,&chatfunc,NULL);
	printf("pthread create success\n");
	pthread_detach(mythread1);
	pthread_detach(mythread2);
	while(1);
	
	return 0;
}

void *acceptpthread(void *arg)
{
	while(1)
	{
		int acceptfd=accept(sockfd,(struct sockaddr *)&clientaddr,&len);
		printf("client [%s]\n",inet_ntoa(clientaddr.sin_addr));
		sem_wait(&sem1);
		UserAddr=clientaddr;
		Useracc=acceptfd;
		sem_post(&sem2);
		event.data.fd=acceptfd;
		event.events=EPOLLIN;
		epoll_ctl(epfd, EPOLL_CTL_ADD, event.data.fd, &event);
		printf("epfd epoll_add success\n");
	}
}

void *chatfunc(void *arg)
{
	while(1)
	{
		int readynum=epoll_wait(epfd,events,5,10000);
		printf("epoll_wait over\n");
		int i=0;
		user_node *p=NULL;
		//char readbuf[256]={0};
		userdata readbuf;
		char sendbuf[256]={0};
		
		for(i=0;i<readynum;i++)
		{
			if(recv(events[i].data.fd,&readbuf,sizeof(readbuf),0)!=0)
			{
				printf("recv over\n");
				printf("name,age\n");
				printf("read name %s\n",readbuf.name);
				printf("read code %d\n",readbuf.code);
				if(readbuf.code==1)
				{
					// userdata Userdata;
					// Userdata.code=-1;
					// memset(Userdata.inputdata,0,128);
					// strncpy(Userdata.name,readbuf+1,32);
					sprintf(sendbuf,"******welcome %s ******",readbuf.name);
					sem_wait(&sem2);
					printf("wait insert\n");
					insert(H,readbuf,UserAddr,Useracc);
					printf("insert\n");
					sem_post(&sem1);
					p=H->next;

					while(p!=NULL)
					{
						send(p->Useracceptfd,sendbuf,256,0);
						//send(events[i].data.fd,sendbuf,256);
						p=p->next;
					}
					printf("send online success\n");
					memset(sendbuf,0,256);
				}
				if(readbuf.code==2)
				{
					//strncpy(username,readbuf+1,32);
					sprintf(sendbuf,"%s : %s ",readbuf.name,readbuf.inputdata);
					p=H->next;
					while(p!=NULL)
					{
						send(p->Useracceptfd,sendbuf,256,0);
						p=p->next;
					}
					memset(sendbuf,0,256);
				}
				if(readbuf.code==3)
				{
			
					sprintf(sendbuf,"******goodbye %s ******",readbuf.name);
					
					p=H;
					while(p->next->Useracceptfd!=events[i].data.fd)
					{
						p=p->next;
						if(p==NULL)
						{
							printf("p is over\n");
						}
					}
					user_node *q=p->next;
					p->next=q->next;
					free(q);
					printf("free %s\n",q->data.name);
					printf("del epfd %d\n",events[i].data.fd);
					epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &event);
					printf("delete success\n");
					p=H->next;
					while(p!=NULL)
					{
						send(p->Useracceptfd,sendbuf,256,0);
						p=p->next;
					}
					memset(sendbuf,0,256);
				}
			}
		}
	}
}

user_node *creat()
{
	user_node *H=malloc(sizeof(user_node));
	H->next=NULL;

	return H;
}

int insert(user_node *H,userdata Userdata,struct sockaddr_in Useraddr,int Useraccfd)
{
	user_node *p=malloc(sizeof(user_node));
	p->data=Userdata;
	p->useraddr=Useraddr;
	p->Useracceptfd=Useraccfd;
	p->next=H->next;
	H->next=p;
	printf("insert success\n");
	return 0;
}
